package ui.swing.combobox;

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URL;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ComboBoxModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;

public class Browser extends JFrame {

	private static final long serialVersionUID = 1890870244971547044L;
	protected JEditorPane m_browser;
	protected MemComboBox m_locator;
	protected AnimatedLabel m_runner;

	public Browser() {
		super("HTML Browser [ComboBox with Memory]");
		setSize(500, 300);

		JPanel p = new JPanel();
		p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
		p.add(new JLabel("Address"));
		p.add(Box.createRigidArea(new Dimension(10, 1)));

		m_locator = new MemComboBox();
		m_locator.load("addresses.dat");
		/*
		m_locator.add("www.ifeng.com.cn");
		m_locator.add("www.ufaud.com");
		m_locator.add("blog.csdn.com/qqlinke");*/
		BrowserListener lst = new BrowserListener();
		m_locator.addActionListener(lst);
		
		p.add(m_locator);
		p.add(Box.createRigidArea(new Dimension(10, 1)));
		m_runner = new AnimatedLabel("p", 5);
		p.add(m_runner);
		getContentPane().add(p, BorderLayout.NORTH);

		m_browser = new JEditorPane();
		m_browser.setEditable(false);
		m_browser.addHyperlinkListener(lst);

		JScrollPane sp = new JScrollPane();
		// sp.getViewport().setView(m_browser);
		sp.getViewport().add(m_browser);

		getContentPane().add(sp, BorderLayout.CENTER);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setVisible(true);
	}

	class BrowserListener implements ActionListener, HyperlinkListener {

		public void actionPerformed(ActionEvent e) {
			String sUrl = (String) m_locator.getSelectedItem();
			if (sUrl == null || sUrl.length() == 0 || m_runner.getRunning()) {
				return;
			}
			BrowserLoader loader = new BrowserLoader(sUrl);
			loader.start();
		}

		public void hyperlinkUpdate(HyperlinkEvent e) {
			if(e.getEventType() != HyperlinkEvent.EventType.ACTIVATED) {
				return;
			}
			URL url = e.getURL();
			if (url == null || m_runner.getRunning()) {
				return;
			}
			BrowserLoader loader = new BrowserLoader(url.toString());
			loader.start();
		}
	}

	class BrowserLoader extends Thread {
		protected String m_sUrl;

		public BrowserLoader(String sUrl) {
			m_sUrl = sUrl;
		}

		@Override
		public void run() {
			setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
			m_runner.setRunning(true);
			URL source;
			try {
				source = new URL(m_sUrl);
				m_browser.setPage(source);
				m_locator.add(m_sUrl);
			} catch (Exception e) {
				JOptionPane.showMessageDialog(Browser.this, "Error: "
						+ e.toString(), "Warning", JOptionPane.WARNING_MESSAGE);
				return;
			} finally {
				m_runner.setRunning(false);
				setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			}
		}
	}
	
	public static void main(String[] args) {
		new Browser();
	}
}

class MemComboBox extends JComboBox {
	private static final long serialVersionUID = -6380807696189747923L;
	public static final int MAX_MEM_LEN = 10;

	public MemComboBox() {
		super();
		setEditable(true);
	}

	// Add to history list
	public void add(String item) {
		removeItem(item);
		insertItemAt(item, 0);
		setSelectedItem(item);
		if (getItemCount() > MAX_MEM_LEN) {
			removeItemAt(getItemCount() - 1);
		}
	}

	// Loads history list from file, using object serialization
	public void load(String fName) {
		try {
			if (getItemCount() > 0) {
				removeAllItems();
			}
			File f = new File(fName);
			if (!f.exists()) {
				return;
			}
			FileInputStream fStream = new FileInputStream(f);
			ObjectInputStream oStream = new ObjectInputStream(fStream);
			Object obj = oStream.readObject();
			if (obj instanceof ComboBoxModel)
				setModel((ComboBoxModel) obj);
			oStream.close();
			fStream.close();
		} catch (Exception e) {
			e.printStackTrace();
			System.err.println("Serialization error: " + e.toString());
		}
	}

	// Stores history list to file, reverse of load() method
	public void save(String fName) {
		try {
			FileOutputStream fStream = new FileOutputStream(fName);
			ObjectOutputStream oStream = new ObjectOutputStream(fStream);
			oStream.writeObject(getModel());
			oStream.flush();
			oStream.close();
			fStream.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
}

// Implements label which presents a “slide show” of several icons in sequence
class AnimatedLabel extends JLabel implements Runnable {
	private static final long serialVersionUID = 3831199215456523879L;
	protected Icon[] m_icons;
	protected int m_index = 0;
	protected volatile boolean m_isRunning;

	public AnimatedLabel(String gifName, int numGifs) {
		m_icons = new Icon[numGifs];
		for (int k = 0; k < numGifs; k++) {
			m_icons[k] = new ImageIcon(getClass().getResource("/resources/images/" + gifName + k + ".gif"));
		}
		setIcon(m_icons[0]);

		Thread tr = new Thread(this);
		tr.setPriority(Thread.MAX_PRIORITY);
		tr.start();

	}

	public void setRunning(boolean isRunning) {
		m_isRunning = isRunning;
	}

	public boolean getRunning() {
		return m_isRunning;
	}

	// In background thread, displays each icon in sequence,
	// sleeping between each one
	public void run() {
		while (true) {
			if (m_isRunning) {
				m_index++;
				if (m_index >= m_icons.length)
					m_index = 0;
				setIcon(m_icons[m_index]);
				Graphics g = getGraphics();
				m_icons[m_index].paintIcon(this, g, 0, 0);
			} else {
				if (m_index > 0) {
					m_index = 0;
					setIcon(m_icons[0]);
				}
			}
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}